/*
 * Copyright (c) 2013-2015 Charkey. All rights reserved.
 *
 * This software is the confidential and proprietary information of Charkey.
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the agreements you entered into with Charkey.
 *
 * Charkey MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *
 * Charkey SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package cn.simastudio.talos.core.exception.base;

import cn.simastudio.talos.common.utils.spring.SpringUtils;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;

/**
 * Usage: 基础异常，定义项目的异常处理机制，集成于运行时异常RuntimeException
 * 保证程序发生错误之后，事务能够回滚。
 *
 * @author Charkey
 * @date 2015/5/11 9:59
 */
public class BaseException extends RuntimeException {

    /**
     * 所属模块
     */
    private String module;

    /**
     * 异常消息国际化编码
     */
    private String msgCode;

    /**
     * 异常编码
     */
    private String errorCode;

    /**
     * 异常消息对应的参数
     */
    private Object[] args;

    /**
     * 默认异常消息
     */
    private String defaultMessage;

    /**
     * 全量参数构造方法
     *
     * @param module         所属模块
     * @param msgCode        异常消息国际化编码
     * @param errorCode      异常编码
     * @param args           异常消息对应的参数
     * @param defaultMessage 默认异常消息
     */
    public BaseException(String module, String msgCode, String errorCode, Object[] args, String defaultMessage) {
        this.module = module;
        this.msgCode = msgCode;
        this.errorCode = errorCode;
        this.args = args == null ? null : args.clone();
        this.defaultMessage = defaultMessage;
    }

    /**
     * 不指定异常所属模块构造方法
     *
     * @param msgCode        异常消息国际化编码
     * @param errorCode      异常编码
     * @param args           异常消息对应的参数
     * @param defaultMessage 默认异常消息
     */
    public BaseException(String msgCode, String errorCode, Object[] args, String defaultMessage) {
        this(null, msgCode, errorCode, args, defaultMessage);
    }

    public BaseException(String msgCode, Object[] args, String defaultMessage) {
        this(msgCode, null, args, defaultMessage);
    }

    public BaseException(String msgCode, String defaultMessage) {
        this(null, msgCode, null, defaultMessage);
    }

    @Override
    public String getMessage() {
        String message = null;
        if (!StringUtils.isEmpty(msgCode)) {
            MessageSource messageSource = SpringUtils.getBean("messageSource");
            LocaleResolver localeResolver = SpringUtils.getBean("localeResolver");
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            // 获取国际化配置文件中code对应的内容，若无相应的code，则抛出NoSuchMessageException；要求：一定要有相应的code配置！
            try {
                message = messageSource.getMessage(msgCode, args, localeResolver.resolveLocale(request));
            } catch (NoSuchMessageException e) {
                // 根据给定的code在国际化文件中找不到消息，这里将消息设置为默认消息defaultMessage
                message = defaultMessage;
            }
        }
        if (message == null) {
            message = defaultMessage;
        }
        return message;
    }


    public String getModule() {
        return module;
    }

    public String getMsgCode() {
        return msgCode;
    }

    public Object[] getArgs() {
        return args.clone();
    }

    public String getDefaultMessage() {
        return defaultMessage;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{")
                .append("\"module\":\"").append(module).append("\",")
                .append("\"code\":\"").append(errorCode).append("\"")
                .append(",\"message\":\"").append(getMessage()).append("\"")
                .append("}");
        return sb.toString();
    }
}
